package cn.cdeden.system.service.impl;

import cn.cdeden.common.core.constant.UserConstants;
import cn.cdeden.common.core.utils.MapstructUtils;
import cn.cdeden.common.core.utils.StreamUtils;
import cn.cdeden.common.core.utils.StringUtils;
import cn.cdeden.common.core.utils.TreeBuildUtils;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.system.domain.SysRole;
import cn.cdeden.system.domain.SysRoleMenu;
import cn.cdeden.system.domain.bo.SysMenuNewUiBo;
import cn.cdeden.system.domain.vo.MetaVo;
import cn.cdeden.system.domain.vo.RouterVo;
import cn.cdeden.system.domain.vo.SysMenuNewUiVo;
import cn.cdeden.system.mapper.SysRoleMapper;
import cn.cdeden.system.mapper.SysRoleMenuMapper;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.cdeden.system.domain.SysMenuNewUi;
import cn.cdeden.system.mapper.SysMenuNewUiMapper;
import cn.cdeden.system.service.SysMenuNewUiService;
@Service
@RequiredArgsConstructor
public class SysMenuNewUiServiceImpl extends ServiceImpl<SysMenuNewUiMapper, SysMenuNewUi> implements SysMenuNewUiService{

    private final SysMenuNewUiMapper sysMenuNewUiMapper;
    private final SysRoleMapper roleMapper;
    private final SysRoleMenuMapper roleMenuMapper;

    @Override
    public List<SysMenuNewUi> selectMenuTreeByUserId(Long userId) {
        List<SysMenuNewUi> menus;
        if (LoginHelper.isSuperAdmin(userId)) {
            menus = baseMapper.selectMenuTreeAll();
        } else {
            menus = baseMapper.selectMenuTreeByUserId(userId);
        }
        return getChildPerms(menus, 0);
    }

    @Override
    public List<SysMenuNewUiVo> selectMenuList(Long userId) {
        return selectMenuList(new SysMenuNewUiBo(), userId);
    }

    @Override
    public List<SysMenuNewUiVo> selectMenuList(SysMenuNewUiBo menu, Long userId) {
        List<SysMenuNewUiVo> menuList;
        // 管理员显示所有菜单信息
        if (LoginHelper.isSuperAdmin(userId)) {
            List<SysMenuNewUi> sysMenuNewUis = sysMenuNewUiMapper.selectList(new LambdaQueryWrapper<SysMenuNewUi>()
                .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenuNewUi::getMenuName, menu.getMenuName())
                .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenuNewUi::getVisible, menu.getVisible())
                .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenuNewUi::getStatus, menu.getStatus())
                .orderByAsc(SysMenuNewUi::getParentId)
                .orderByAsc(SysMenuNewUi::getOrderNum));
            menuList = MapstructUtils.convert(sysMenuNewUis, SysMenuNewUiVo.class);
        } else {
            QueryWrapper<SysMenuNewUi> wrapper = Wrappers.query();
            wrapper.inSql("r.role_id", "select role_id from sys_user_role where user_id = " + userId)
                .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName())
                .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible())
                .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus())
                .orderByAsc("m.parent_id")
                .orderByAsc("m.order_num");
            List<SysMenuNewUi> list = sysMenuNewUiMapper.selectList(wrapper);
            menuList = MapstructUtils.convert(list, SysMenuNewUiVo.class);
        }
        return menuList;
    }

    @Override
    public SysMenuNewUiVo selectMenuById(Long menuId) {
        return MapstructUtils.convert(sysMenuNewUiMapper.selectById(menuId), SysMenuNewUiVo.class);
    }

    @Override
    public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuNewUiVo> menus) {
        if (CollUtil.isEmpty(menus)) {
            return CollUtil.newArrayList();
        }
        return TreeBuildUtils.build(menus, (menu, tree) ->
            tree.setId(menu.getMenuId())
                .setParentId(menu.getParentId())
                .setName(menu.getMenuName())
                .setWeight(menu.getOrderNum()));
    }

    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectById(roleId);
        return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly());
    }

    @Override
    public int insertMenu(SysMenuNewUiBo bo) {
        SysMenuNewUi menu = MapstructUtils.convert(bo, SysMenuNewUi.class);
        return baseMapper.insert(menu);
    }

    @Override
    public int updateMenu(SysMenuNewUiBo bo) {
        SysMenuNewUi menu = MapstructUtils.convert(bo, SysMenuNewUi.class);
        return baseMapper.updateById(menu);
    }

    @Override
    public boolean checkMenuNameUnique(SysMenuNewUiBo menu) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysMenuNewUi>()
            .eq(SysMenuNewUi::getMenuName, menu.getMenuName())
            .eq(SysMenuNewUi::getParentId, menu.getParentId())
            .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenuNewUi::getMenuId, menu.getMenuId()));
        return !exist;
    }

    @Override
    public boolean hasChildByMenuId(Long menuId) {
        return baseMapper.exists(new LambdaQueryWrapper<SysMenuNewUi>().eq(SysMenuNewUi::getParentId, menuId));
    }

    @Override
    public boolean checkMenuExistRole(Long menuId) {
        return roleMenuMapper.exists(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
    }

    @Override
    public int deleteMenuById(Long menuId) {
        return baseMapper.deleteById(menuId);
    }

    @Override
    public List<RouterVo> buildMenus(List<SysMenuNewUi> menus) {
        List<RouterVo> routers = new LinkedList<>();
        for (SysMenuNewUi menu : menus) {
            String name = menu.getRouteName() + menu.getMenuId();
            RouterVo router = new RouterVo();
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(name);
            router.setPath(menu.getRouterPath());
            router.setComponent(menu.getComponentInfo());
            router.setQuery(menu.getQueryParam());
            router.setForward(menu.getForward());
            router.setLocation(menu.getLocation());
            router.setFloating(menu.getFloating());
            router.setAbbreviation(menu.getAbbreviation());
            router.setIconColor(menu.getIconColor());
            router.setIdentifying(menu.getIdentifying());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
            List<SysMenuNewUi> cMenus = menu.getChildren();
            if (CollUtil.isNotEmpty(cMenus) && (UserConstants.TYPE_DIR.equals(menu.getMenuType()) || UserConstants.TYPE_MENU.equals(menu.getMenuType()))) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            } else if (menu.isMenuFrame()) {
                String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId();
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(frameName);
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQueryParam());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                String routerPath = SysMenuNewUi.innerLinkReplaceEach(menu.getPath());
                String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId();
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(innerLinkName);
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        List<String> perms = baseMapper.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(StringUtils.splitList(perm.trim()));
            }
        }
        return permsSet;
    }


    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    private List<SysMenuNewUi> getChildPerms(List<SysMenuNewUi> list, int parentId) {
        List<SysMenuNewUi> returnList = new ArrayList<>();
        for (SysMenuNewUi t : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }


    /**
     * 递归列表
     */
    private void recursionFn(List<SysMenuNewUi> list, SysMenuNewUi t) {
        // 得到子节点列表
        List<SysMenuNewUi> childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId()));
        t.setChildren(childList);
        for (SysMenuNewUi tChild : childList) {
            // 判断是否有子节点
            if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) {
                recursionFn(list, tChild);
            }
        }
    }
}
